package edu.stanford.bmir.protege.web.client.ui.ontology.stkos.cutter.option;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.google.gwt.core.client.GWT;
import com.google.gwt.dom.client.Element;
import com.google.gwt.dom.client.Style.Display;
import com.google.gwt.event.dom.client.ChangeEvent;
import com.google.gwt.event.dom.client.ChangeHandler;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.logical.shared.ValueChangeEvent;
import com.google.gwt.event.logical.shared.ValueChangeHandler;
import com.google.gwt.uibinder.client.UiBinder;
import com.google.gwt.uibinder.client.UiField;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.HTMLPanel;
import com.google.gwt.user.client.ui.HasEnabled;
import com.google.gwt.user.client.ui.ListBox;
import com.google.gwt.user.client.ui.RadioButton;
import com.google.gwt.user.client.ui.TextBox;

import edu.stanford.bmir.protege.web.client.dispatch.DispatchServiceManager;
import edu.stanford.bmir.protege.web.client.project.Project;
import edu.stanford.bmir.protege.web.client.rpc.stkosutil.StkosUtilServiceManager;
import edu.stanford.bmir.protege.web.client.rpc.stkosutil.common.ItemSelector;
import edu.stanford.bmir.protege.web.client.rpc.stkosutil.common.MatchLevel;
import edu.stanford.bmir.protege.web.client.rpc.stkosutil.cutter.CancelCutterResult;
import edu.stanford.bmir.protege.web.client.rpc.stkosutil.cutter.CuttingMode;
import edu.stanford.bmir.protege.web.client.rpc.stkosutil.cutter.CuttingOptions;
import edu.stanford.bmir.protege.web.client.rpc.stkosutil.cutter.CuttingResult;
import edu.stanford.bmir.protege.web.client.rpc.stkosutil.cutter.CuttingScope;
import edu.stanford.bmir.protege.web.client.rpc.stkosutil.cutter.RemoveEntityResult;
import edu.stanford.bmir.protege.web.client.rpc.stkosutil.cutter.actions.CancelCutterAction;
import edu.stanford.bmir.protege.web.client.ui.library.msgbox.MessageBox;
import edu.stanford.bmir.protege.web.client.ui.library.msgbox.YesNoHandler;
import edu.stanford.bmir.protege.web.client.ui.ontology.stkos.common.GWTExtUtil;
import edu.stanford.bmir.protege.web.client.ui.ontology.stkos.common.interfaces.StkosCallBack;
import edu.stanford.bmir.protege.web.client.ui.projectmanager.DownloadProjectRequestHandler;
import edu.stanford.bmir.protege.web.client.ui.projectmanager.DownloadProjectRequestHandlerImpl;
import edu.stanford.bmir.protege.web.shared.project.GetAvailableProjectsAction;
import edu.stanford.bmir.protege.web.shared.project.GetAvailableProjectsResult;
import edu.stanford.bmir.protege.web.shared.project.ProjectDetails;

public class StkosCutterOptionView extends Composite implements HasEnabled {

	public enum StkosCutterOptionViewButtonType {

		AUTOCUTTER("自动裁切"),

		SHOWCLASS("显示类"),

		SHOWPROPERTY("显示属性"),

		SHOWINDIVIDUAL("显示个体"),

		PHYSICALCUTTING("物理裁切"),

		EXPORTRESULT("导出结果"),

		CANCEL("取消")

		;

		private String text;

		private StkosCutterOptionViewButtonType(String text) {
			this.text = text;
		}

		public String getButtonText() {
			return text;
		}
	}

	public enum StkosCutterOptionViewListBoxType {

		ACCORDINGONTOLOGY("参考本体");

		private String text;

		private StkosCutterOptionViewListBoxType(String text) {
			this.text = text;
		}

		public String getButtonText() {
			return text;
		}
	}

	public enum StkosCutterOptionViewRadioButtonType {

		SEARCHCONDITION("检索条件"),

		REFERTOPROJECT("参考本体");

		private String text;

		private StkosCutterOptionViewRadioButtonType(String text) {
			this.text = text;
		}

		public String getButtonText() {
			return text;
		}
	}

	interface StkosCutterOptionViewUiBinder extends
			UiBinder<HTMLPanel, StkosCutterOptionView> {
	}

	private static StkosCutterOptionViewUiBinder ourUiBinder = GWT
			.create(StkosCutterOptionViewUiBinder.class);

	private Project project;

	private HTMLPanel rootElement;

	private List<ProjectDetails> availableProjectDetails;

	private Map<StkosCutterOptionViewButtonType, StkosCallBack> btnHandlers = new HashMap<StkosCutterOptionViewButtonType, StkosCallBack>();

	private Map<StkosCutterOptionViewListBoxType, StkosCallBack> listBoxHandlers = new HashMap<StkosCutterOptionViewListBoxType, StkosCallBack>();

	private Map<StkosCutterOptionViewRadioButtonType, StkosCallBack> radioButtonHandlers = new HashMap<StkosCutterOptionViewRadioButtonType, StkosCallBack>();

	/* 裁切范围 */
	/** 全部类 **/
	@UiField
	protected RadioButton cutterRangeAllClass;
	/** 全部属性 **/
	@UiField
	protected RadioButton cutterRangeAllProperty;
	/** 全部个体 **/
	@UiField
	protected RadioButton cutterRangeAllIndividual;
	/** 当前类及子类 **/
	@UiField
	protected RadioButton cutterRangeCurrentClsAndSubCls;
	/** 当前属性及其子属性 **/
	@UiField
	protected RadioButton cutterRangeCurrentPropAndSubProp;

	/* 裁切方式 */
	/** 检索条件 **/
	@UiField
	protected RadioButton cutterWaySearchCondition;
	/** 参考本体 **/
	@UiField
	protected RadioButton cutterWayReferToProject;

	/** 关 键 词 **/
	@UiField
	protected TextBox cutterKeyword;
	/** 精确匹配 **/
	@UiField
	protected RadioButton cutterKeywordExactMatching;
	/** 模糊匹配 **/
	@UiField
	protected RadioButton cutterKeywordFuzzyMatching;

	/** 参考本体 **/
	@UiField
	protected ListBox cutterReferToOntology;

	/** 裁切未匹配项 **/
	@UiField
	protected RadioButton cutterReferToOntoUnMatching;
	/** 裁切匹配项 **/
	@UiField
	protected RadioButton cutterReferToOntoMatching;

	/* 按钮 */
	@UiField
	protected Button btnAutoCutter;
	@UiField
	protected Button btnShowClass;
	@UiField
	protected Button btnShowProperty;
	@UiField
	protected Button btnShowIndividual;
	@UiField
	protected Button btnPhysicalCutting;
	@UiField
	protected Button btnExportResult;
	/** 取消 */
	@UiField
	protected Button btnCancel;

	public StkosCutterOptionView(Project project) {
		this.project = project;

		rootElement = ourUiBinder.createAndBindUi(this);
		initWidget(rootElement);

		registerBtnEventHandler();
		registerRadioButtonEventHandler();
		registerListBoxEventHandler();
		setCutterReferToOntologyItems();
	}

	@Override
	public boolean isEnabled() {
		return true;
	}

	@Override
	public void setEnabled(boolean enabled) {
		btnAutoCutter.setEnabled(enabled);
		btnShowClass.setEnabled(enabled);
		btnShowProperty.setEnabled(enabled);
		btnShowIndividual.setEnabled(enabled);
		btnPhysicalCutting.setEnabled(enabled);
		btnExportResult.setEnabled(enabled);
		btnCancel.setEnabled(enabled);
	}

	protected void registerBtnEventHandler() {
		ClickHandler clickHandler = new ClickHandler() {
			@Override
			public void onClick(ClickEvent event) {
				if (event.getSource().equals(btnAutoCutter)) {
					autoCutter();
				} else if (event.getSource().equals(btnShowClass)) {
					showClass();
				} else if (event.getSource().equals(btnShowProperty)) {
					showProperty();
				} else if (event.getSource().equals(btnShowIndividual)) {
					showIndividual();
				} else if (event.getSource().equals(btnPhysicalCutting)) {
					physicalCutting();
				} else if (event.getSource().equals(btnExportResult)) {
					exportResult();
				} else if (event.getSource().equals(btnCancel)) {
					cancel();
				}
			}
		};

		btnAutoCutter.addClickHandler(clickHandler);
		btnShowClass.addClickHandler(clickHandler);
		btnShowProperty.addClickHandler(clickHandler);
		btnShowIndividual.addClickHandler(clickHandler);
		btnPhysicalCutting.addClickHandler(clickHandler);
		btnExportResult.addClickHandler(clickHandler);
		btnCancel.addClickHandler(clickHandler);
	}

	protected CuttingOptions getOptions() {
		CuttingOptions options = new CuttingOptions();
		// 裁切范围
		if (cutterRangeAllClass.getValue()) {
			options.setCuttingScope(CuttingScope.ALL_CLASSES);
		}
		if (cutterRangeAllProperty.getValue()) {
			options.setCuttingScope(CuttingScope.ALL_PROPERTIES);
		}
		if (cutterRangeAllIndividual.getValue()) {
			options.setCuttingScope(CuttingScope.ALL_INDIVIDUALS);
		}
		if (cutterRangeCurrentClsAndSubCls.getValue()) {
			options.setCuttingScope(CuttingScope.SELECTED_CLASS_TREE);
		}
		if (cutterRangeCurrentPropAndSubProp.getValue()) {
			options.setCuttingScope(CuttingScope.SELECTED_PROPERTY_TREE);
		}

		if (cutterReferToOntoUnMatching.getValue()) {
			options.setItemSelector(ItemSelector.NOT_MATCHED_ITEMS);
		} else if (cutterReferToOntoMatching.getValue()) {
			options.setItemSelector(ItemSelector.MATCHED_ITEMS);
		}

		// 裁切方式
		if (cutterWaySearchCondition.getValue()) {
			options.setCuttingMode(CuttingMode.SEARCH);

			options.setSearch(cutterKeyword.getValue());

			if (cutterKeywordExactMatching.getValue()) {
				options.setMatchLevel(MatchLevel.CASE_INSENSITIVE);
			} else if (cutterKeywordFuzzyMatching.getValue()) {
				options.setMatchLevel(MatchLevel.INCLUSIVE);
			}
		}
		if (cutterWayReferToProject.getValue()) {
			options.setCuttingMode(CuttingMode.REF_PROJECT);

			String refProjectName = null;
			if (cutterReferToOntology.getSelectedIndex() > -1) {
				refProjectName = cutterReferToOntology
						.getValue(cutterReferToOntology.getSelectedIndex());
			}
			options.setRefProjectName(refProjectName);
		}
		return options;
	}

	protected void autoCutter() {
		String projectName = project.getProjectId().getId();
		CuttingOptions options = getOptions();
		if (CuttingMode.SEARCH.equals(options.getCuttingMode())) {
			if (options.getSearch() == null
					|| "".equals(options.getSearch().trim())) {
				MessageBox.showAlert("提示", "请输入有效的关键字");
				return;
			}
		} else if (CuttingMode.REF_PROJECT.equals(options.getCuttingMode())) {
			if (options.getRefProjectName() == null
					|| GWTExtUtil.DEFAULTLISTBOXITEMVALUEID.equals(options
							.getRefProjectName())) {
				MessageBox.showAlert("提示", "请选择一个参照本体");
				return;
			}
		}

		GWTExtUtil.showProgressMonitor("提示", "程序正在处理、请稍候...");

		AsyncCallback<CuttingResult> callback = new AsyncCallback<CuttingResult>() {
			@Override
			public void onFailure(Throwable caught) {
				MessageBox.showAlert("自动裁切", "自动裁切失败、详情：" + caught);
				doAutoCutterHandler(null);
			}

			@Override
			public void onSuccess(CuttingResult result) {
				if (result == null) {
					MessageBox.showAlert("自动裁切", "自动裁切失败返回结果为空!");
				}
				doAutoCutterHandler(result);
				btnCancel.setEnabled(true);
			}
		};
		StkosUtilServiceManager.getInstance().cutOntology(projectName, options,
				callback);
	}

	protected void doAutoCutterHandler(CuttingResult result) {
		GWTExtUtil.hideProgressMonitor("提示", "程序处理完成!", 850);

		StkosCallBack handler = btnHandlers
				.get(StkosCutterOptionViewButtonType.AUTOCUTTER);
		if (handler != null) {
			handler.onCallBack(result);
		}
	}

	protected void showClass() {
		StkosCallBack handler = btnHandlers
				.get(StkosCutterOptionViewButtonType.SHOWCLASS);
		if (handler != null) {
			handler.onCallBack();
		}
	}

	protected void showProperty() {
		StkosCallBack handler = btnHandlers
				.get(StkosCutterOptionViewButtonType.SHOWPROPERTY);
		if (handler != null) {
			handler.onCallBack();
		}
	}

	protected void showIndividual() {
		StkosCallBack handler = btnHandlers
				.get(StkosCutterOptionViewButtonType.SHOWINDIVIDUAL);
		if (handler != null) {
			handler.onCallBack();
		}
	}

	protected void physicalCutting() {
		String projectName = project.getProjectId().getId();
		AsyncCallback<RemoveEntityResult> callback = new AsyncCallback<RemoveEntityResult>() {
			@Override
			public void onFailure(Throwable caught) {
				MessageBox.showAlert("物理裁切", "物理裁切失败、详情：" + caught);
			}

			@Override
			public void onSuccess(RemoveEntityResult result) {
				if (result == null) {
					MessageBox.showAlert("物理裁切", "物理裁切失败返回结果为空!");
					return;
				}
				doPhysicalCuttingHandler(result);
			}
		};

		StkosUtilServiceManager.getInstance().removeCutEntities(projectName,
				callback);
	}

	protected void doPhysicalCuttingHandler(
			RemoveEntityResult removeEntityResult) {
		if (removeEntityResult != null) {
			int removedClassNum = removeEntityResult.getRemovedClassNum() - 1;
			if (removedClassNum < 0) {
				removedClassNum = 0;
			}
			String subm = "删除类：" + removedClassNum + "个<br/><br/>删除属性："
					+ removeEntityResult.getRemovedPropertyNum()
					+ "个<br/><br/>删除个体："
					+ removeEntityResult.getRemovedIndividualNum() + "个";
			MessageBox.showMessage("统计结果展示", subm);
		}

		StkosCallBack handler = btnHandlers
				.get(StkosCutterOptionViewButtonType.PHYSICALCUTTING);
		if (handler != null) {
			handler.onCallBack(removeEntityResult);
		}
	}

	protected void exportResult() {
		DownloadProjectRequestHandler downloadProjectRequestHandler = new DownloadProjectRequestHandlerImpl();
		downloadProjectRequestHandler.handleProjectDownloadRequest(project
				.getProjectId());
		doExportHandler();
	}

	protected void cancel() {
		final String projectName = project.getProjectId().getId();
		YesNoHandler ynHandler = new YesNoHandler() {
			@Override
			public void handleYes() {
				cancelOperation(projectName);
			}

			@Override
			public void handleNo() {
			}
		};
		MessageBox.showYesNoConfirmBox("取消操作", "你确定要取消裁切操作吗?", ynHandler);
	}

	protected void cancelOperation(String projectName) {
		if (projectName == null) {
			MessageBox.showAlert("提示", "必要信息不完整,操作失败!");
			btnCancel.setEnabled(false);
			return;
		}

		GWTExtUtil.showProgressMonitor("提示", "程序正在处理、请稍候...");

		CancelCutterAction action = new CancelCutterAction();
		AsyncCallback<CancelCutterResult> callback = new AsyncCallback<CancelCutterResult>() {
			@Override
			public void onFailure(Throwable caught) {
				MessageBox.showAlert("取消操作", "取消操作处理失败、详情：" + caught);
				doCancelHandler(null);
			}

			@Override
			public void onSuccess(CancelCutterResult result) {
				doCancelHandler(result);
			}
		};
		StkosUtilServiceManager.getInstance().cancelCutter(projectName, action,
				callback);
	}

	protected void doCancelHandler(CancelCutterResult result) {
		GWTExtUtil.hideProgressMonitor("提示", "程序处理完成!", 1);

		if (result != null) {
			MessageBox.showMessage(
					"取消裁切操作成功",
					"共删除裁切类" + result.getDelClass() + "个,裁切个体"
							+ result.getDelIndividual() + "个,裁切属性"
							+ result.getDelProperty() + "个!");
		} else {
			MessageBox.showAlert("取消裁切操作结束", "返回结果为空!");
		}
		btnCancel.setEnabled(false);

		if (btnHandlers.get(StkosCutterOptionViewButtonType.CANCEL) != null) {
			btnHandlers.get(StkosCutterOptionViewButtonType.CANCEL).onCallBack(
					result);
		}
	}

	protected void doExportHandler() {
		StkosCallBack handler = btnHandlers
				.get(StkosCutterOptionViewButtonType.EXPORTRESULT);
		if (handler != null) {
			handler.onCallBack();
		}
	}

	protected void registerRadioButtonEventHandler() {
		ValueChangeHandler<Boolean> valueChange = new ValueChangeHandler<Boolean>() {
			@Override
			public void onValueChange(ValueChangeEvent<Boolean> event) {
				if (event.getSource().equals(cutterWaySearchCondition)) {
					StkosCallBack handler1 = radioButtonHandlers
							.get(StkosCutterOptionViewRadioButtonType.SEARCHCONDITION);
					if (handler1 != null) {
						handler1.onCallBack();
					}
					showSearchCondition();
				} else if (event.getSource().equals(cutterWayReferToProject)) {
					StkosCallBack handler2 = radioButtonHandlers
							.get(StkosCutterOptionViewRadioButtonType.REFERTOPROJECT);
					if (handler2 != null) {
						handler2.onCallBack();
					}
					showReferToProject();
				}
			}
		};

		cutterWaySearchCondition.addValueChangeHandler(valueChange);
		cutterWayReferToProject.addValueChangeHandler(valueChange);
	}

	protected void showSearchCondition() {
		Element el2 = rootElement
				.getElementById("stkoscutterrefertoontologyTr");
		el2.getStyle().setDisplay(Display.NONE);

		Element el = rootElement.getElementById("stkoscutterkeywordTr");
		el.getStyle().setProperty("display", "table-row");
	}

	protected void showReferToProject() {
		Element el = rootElement.getElementById("stkoscutterkeywordTr");
		el.getStyle().setDisplay(Display.NONE);

		Element el2 = rootElement
				.getElementById("stkoscutterrefertoontologyTr");
		el2.getStyle().setProperty("display", "table-row");
	}

	protected void registerListBoxEventHandler() {
		ChangeHandler changeHandler = new ChangeHandler() {
			@Override
			public void onChange(ChangeEvent event) {
				if (event.getSource().equals(cutterReferToOntology)) {
					StkosCallBack handler = listBoxHandlers
							.get(StkosCutterOptionViewListBoxType.ACCORDINGONTOLOGY);
					if (handler != null) {
						handler.onCallBack();
					}
				}
			}
		};
		cutterReferToOntology.addChangeHandler(changeHandler);
	}

	protected void setCutterReferToOntologyItems() {
		availableProjectDetails = null;
		cutterReferToOntology.clear();

		DispatchServiceManager.get().execute(new GetAvailableProjectsAction(),
				new AsyncCallback<GetAvailableProjectsResult>() {
					@Override
					public void onFailure(Throwable caught) {
						GWT.log("Loading Project List Error!", caught);
					}

					@Override
					public void onSuccess(GetAvailableProjectsResult result) {
						if (result == null || result.getDetails() == null
								|| result.getDetails().size() == 0) {
							GWT.log("Please create some project!");
						} else {
							availableProjectDetails = new ArrayList<ProjectDetails>();

							String pid = project.getProjectId().getId();

							for (ProjectDetails pd : result.getDetails()) {
								try {
									if (!pd.isInTrash()
											&& !pd.getProjectId().getId()
													.equals(pid)) {
										availableProjectDetails.add(pd);
									}
								} catch (Exception e) {
								}
							}

							if (availableProjectDetails.size() > 0) {
								cutterReferToOntology.addItem("请选择本体",
										GWTExtUtil.DEFAULTLISTBOXITEMVALUEID);
								for (ProjectDetails pd : availableProjectDetails) {
									try {
										cutterReferToOntology.addItem(pd
												.getDisplayName(), pd
												.getProjectId().getId());
									} catch (Exception e) {
									}
								}
							}
						}
					}
				});
	}

	public void setBtnHandler(StkosCutterOptionViewButtonType type,
			StkosCallBack cb) {
		if (type == null || cb == null) {
			return;
		}
		btnHandlers.remove(type);
		btnHandlers.put(type, cb);
	}

	public void setListBoxHandler(StkosCutterOptionViewListBoxType type,
			StkosCallBack cb) {
		if (type == null || cb == null) {
			return;
		}
		listBoxHandlers.remove(type);
		listBoxHandlers.put(type, cb);
	}

	public void setRadioButtonHandler(
			StkosCutterOptionViewRadioButtonType type, StkosCallBack cb) {
		if (type == null || cb == null) {
			return;
		}
		radioButtonHandlers.remove(type);
		radioButtonHandlers.put(type, cb);
	}

	public boolean isRadioCutterWaySearchConditionChecked() {
		boolean f = false;
		if (cutterWaySearchCondition != null
				&& cutterWaySearchCondition.getValue()) {
			f = true;
		}
		return f;
	}

	public boolean isRadioCutterWayReferToProjectChecked() {
		boolean f = false;
		if (cutterWayReferToProject != null
				&& cutterWayReferToProject.getValue()) {
			f = true;
		}
		return f;
	}

	public ProjectDetails getReferToProjectDetails() {
		ProjectDetails projectDetails = null;
		if (availableProjectDetails != null && cutterWayReferToProject != null
				&& cutterWayReferToProject.getValue()) {
			String referToProjectId = null;
			if (cutterReferToOntology != null
					&& cutterReferToOntology.getSelectedIndex() > -1) {
				referToProjectId = cutterReferToOntology
						.getValue(cutterReferToOntology.getSelectedIndex());
			}
			for (ProjectDetails pd : availableProjectDetails) {
				try {
					if (pd.getProjectId().getId().equals(referToProjectId)) {
						projectDetails = pd;
						break;
					}
				} catch (Exception e) {
				}
			}
		}
		return projectDetails;
	}
}
